#include <cmath>
#include <thrust\device_ptr.h>
#include <thrust\fill.h>

#include <utility\cuda_utils.h>
#include "BV.h"

namespace gc {
	__host__ __device__ void AABB::merge(const AABB &b) {
		ptMin = makePoint3f(fmin(ptMin.x, b.ptMin.x), fmin(ptMin.y, b.ptMin.y), fmin(ptMin.z, b.ptMin.z));
		ptMax = makePoint3f(fmax(ptMax.x, b.ptMax.x), fmax(ptMax.y, b.ptMax.y), fmax(ptMax.z, b.ptMax.z));
	}

	__host__ __device__ void AABB::merge(const Point3f &b) {
		ptMin = makePoint3f(fmin(ptMin.x, b.x), fmin(ptMin.y, b.y), fmin(ptMin.z, b.z));
		ptMax = makePoint3f(fmax(ptMax.x, b.x), fmax(ptMax.y, b.y), fmax(ptMax.z, b.z));
	}

	__host__ __device__ void AABB::merge(const Float x, const Float y, const Float z) {
		ptMin = makePoint3f(fmin(ptMin.x, x), fmin(ptMin.y, y), fmin(ptMin.z, z));
		ptMax = makePoint3f(fmax(ptMax.x, x), fmax(ptMax.y, y), fmax(ptMax.z, z));
	}

	__host__ __device__ bool AABB::overlap(const AABB &b) const {
		if (b.ptMin.x > ptMax.x || b.ptMax.x < ptMin.x) return false;
		if (b.ptMin.y > ptMax.y || b.ptMax.y < ptMin.y) return false;
		if (b.ptMin.z > ptMax.z || b.ptMax.z < ptMin.z) return false;
		return true;
	}

	__host__ __device__ void AABB::reset() {
		ptMin = makePoint3f(FMAX, FMAX, FMAX);
		ptMax = makePoint3f(-FMAX, -FMAX, -FMAX);
	}

	__host__ std::string AABB::toString() {
		char content[100];
		sprintf(content, "{(%.2f,%.2f,%.2f), (%.2f,%.2f,%.2f)}", ptMin.x, ptMin.y, ptMin.z, ptMax.x, ptMax.y, ptMax.z);
		return std::string(content);
	}

	__host__ __device__ AABB_SOA::AABB_SOA() :minx(NULL), miny(NULL), minz(NULL), maxx(NULL), maxy(NULL), maxz(NULL) {}

	void AABB_SOA::malloc(uint size) {
		this->size = size;
		checkCudaErrors(GPUMalloc(minx, sizeof(Float)*size));
		checkCudaErrors(GPUMalloc(miny, sizeof(Float)*size));
		checkCudaErrors(GPUMalloc(minz, sizeof(Float)*size));
		checkCudaErrors(GPUMalloc(maxx, sizeof(Float)*size));
		checkCudaErrors(GPUMalloc(maxy, sizeof(Float)*size));
		checkCudaErrors(GPUMalloc(maxz, sizeof(Float)*size));
	}

	void AABB_SOA::free() {
		checkCudaErrors(cudaFree(minx));
		checkCudaErrors(cudaFree(miny));
		checkCudaErrors(cudaFree(minz));
		checkCudaErrors(cudaFree(maxx));
		checkCudaErrors(cudaFree(maxy));
		checkCudaErrors(cudaFree(maxz));
	}

	void AABB_SOA::reset() {
		thrust::fill(thrust::device_ptr<Float>(minx), thrust::device_ptr<Float>(minx) + size, FMAX);
		thrust::fill(thrust::device_ptr<Float>(miny), thrust::device_ptr<Float>(miny) + size, FMAX);
		thrust::fill(thrust::device_ptr<Float>(minz), thrust::device_ptr<Float>(minz) + size, FMAX);

		thrust::fill(thrust::device_ptr<Float>(maxx), thrust::device_ptr<Float>(maxx) + size, -FMAX);
		thrust::fill(thrust::device_ptr<Float>(maxy), thrust::device_ptr<Float>(maxy) + size, -FMAX);
		thrust::fill(thrust::device_ptr<Float>(maxz), thrust::device_ptr<Float>(maxz) + size, -FMAX);
	}
}
